﻿using System.Web.Mvc;
using Nop.Plugin.Widgets.GoogleAdwords.Models;
using Nop.Services.Configuration;
using Nop.Web.Framework.Controllers;
using System;
using System.Linq;
using System.Globalization;
using Nop.Core.Domain.Orders;
using Nop.Core;
using Nop.Services.Orders;
using Nop.Services.Logging;
using Nop.Services.Catalog;
using System.Text;
using Nop.Core.Domain;
using Nop.Services.Stores;
using System.Collections.Generic;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Tax;

namespace Nop.Plugin.Widgets.GoogleAdwords.Controllers
{
    public class WidgetsGoogleAdwordsController : BasePluginController
    {
        private readonly IWorkContext _workContext;
        private readonly IStoreContext _storeContext;
        private readonly IStoreService _storeService;
        private readonly ISettingService _settingService;
        private readonly IOrderService _orderService;
        private readonly IOrderTotalCalculationService _orderTotalCalculationService;
        private readonly ICategoryService _categoryService;
        private readonly ILogger _logger;
        private readonly StoreInformationSettings _storeInformationSettings;

        private readonly CultureInfo _usCulture;

        public WidgetsGoogleAdwordsController(IWorkContext workContext,
            IStoreContext storeContext,
            IStoreService storeService,
            ISettingService settingService,
            IOrderService orderService,
            IOrderTotalCalculationService orderTotalCalculationService,
            ICategoryService categoryService,
            ILogger logger,
            StoreInformationSettings storeInformationSettings)
        {
            this._workContext = workContext;
            this._storeContext = storeContext;
            this._storeService = storeService;
            this._settingService = settingService;
            this._orderService = orderService;
            this._orderTotalCalculationService = orderTotalCalculationService;
            this._categoryService = categoryService;
            this._logger = logger;
            this._storeInformationSettings = storeInformationSettings;
            this._usCulture = new CultureInfo("en-US");
        }

        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure()
        {
            //load settings for a chosen store scope
            var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
            var googleAdwordsSettings = _settingService.LoadSetting<GoogleAdwordsSettings>(storeScope);
            var model = new ConfigurationModel();
            model.ConversionId = googleAdwordsSettings.ConversionId;
            model.ConversionLabel = googleAdwordsSettings.ConversionLabel;
            model.ConversionScript = googleAdwordsSettings.ConversionScript;
            model.RemarketingScript = googleAdwordsSettings.RemarketingScript;

            model.DefaultRemarketingScript = GoogleAdwordsPlugin.DEFAULT_CONVERSION_SCRIPT;
            model.DefaultConversionScript = GoogleAdwordsPlugin.DEFAULT_CONVERSION_SCRIPT;

            model.ActiveStoreScopeConfiguration = storeScope;

            if (storeScope > 0)
            {
                model.ConversionId_OverrideForStore = _settingService.SettingExists(googleAdwordsSettings, x => x.ConversionId, storeScope);
                model.ConversionLabel_OverrideForStore = _settingService.SettingExists(googleAdwordsSettings, x => x.ConversionLabel, storeScope);
                model.ConversionScript_OverrideForStore = _settingService.SettingExists(googleAdwordsSettings, x => x.ConversionScript, storeScope);
                model.RemarketingScript_OverrideForStore = _settingService.SettingExists(googleAdwordsSettings, x => x.RemarketingScript, storeScope);
            }

            return View("Nop.Plugin.Widgets.GoogleAdwords.Views.WidgetsGoogleAdwords.Configure", model);
        }

        [HttpPost]
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure(ConfigurationModel model)
        {
            if (!ModelState.IsValid)
                return Configure();

            //load settings for a chosen store scope
            var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
            var googleAdwordsSettings = _settingService.LoadSetting<GoogleAdwordsSettings>(storeScope);

            //save settings
            googleAdwordsSettings.ConversionId = model.ConversionId;
            googleAdwordsSettings.ConversionLabel = model.ConversionLabel;
            googleAdwordsSettings.ConversionScript = model.ConversionScript;
            googleAdwordsSettings.RemarketingScript = model.RemarketingScript;

            /* We do not clear cache after each setting update.
          * This behavior can increase performance because cached settings will not be cleared 
          * and loaded from database after each update */
            if (model.ConversionId_OverrideForStore || storeScope == 0)
                _settingService.SaveSetting(googleAdwordsSettings, x => x.ConversionId, storeScope, false);
            else if (storeScope > 0)
                _settingService.DeleteSetting(googleAdwordsSettings, x => x.ConversionId, storeScope);

            if (model.ConversionLabel_OverrideForStore || storeScope == 0)
                _settingService.SaveSetting(googleAdwordsSettings, x => x.ConversionLabel, storeScope, false);
            else if (storeScope > 0)
                _settingService.DeleteSetting(googleAdwordsSettings, x => x.ConversionLabel, storeScope);

            if (model.ConversionScript_OverrideForStore || storeScope == 0)
                _settingService.SaveSetting(googleAdwordsSettings, x => x.ConversionScript, storeScope, false);
            else if (storeScope > 0)
                _settingService.DeleteSetting(googleAdwordsSettings, x => x.ConversionScript, storeScope);

            if (model.RemarketingScript_OverrideForStore || storeScope == 0)
                _settingService.SaveSetting(googleAdwordsSettings, x => x.RemarketingScript, storeScope, false);
            else if (storeScope > 0)
                _settingService.DeleteSetting(googleAdwordsSettings, x => x.RemarketingScript, storeScope);

            //now clear settings cache
            _settingService.ClearCache();

            return Configure();
        }

        [ChildActionOnly]
        public ActionResult PublicInfo(string widgetZone)
        {
            string globalScript = "";
            var routeData = ((System.Web.UI.Page)this.HttpContext.CurrentHandler).RouteData;
            string controller = routeData.Values["controller"].ToString().ToLowerInvariant();
            string action = routeData.Values["action"].ToString().ToLowerInvariant();

            try
            {
                switch (controller)
                {
                    case "home":
                        if (action.Equals("index", StringComparison.InvariantCultureIgnoreCase))
                        {
                            globalScript += GetRemarketingScript("home", null, null, null);
                        }
                        break;
                    case "catalog":
                        if (action.Equals("category", StringComparison.InvariantCultureIgnoreCase))
                        {
                            string currentCategoryName = "";
                            string currentCategoryIdStr = routeData.Values["categoryId"].ToString();
                            if (!string.IsNullOrEmpty(currentCategoryIdStr))
                            {
                                //productId = categoryId;
                                var category = _categoryService.GetCategoryById(int.Parse(currentCategoryIdStr));
                                currentCategoryName = category.Name;
                                //currentCategoryName = category.GetLocalized(x => x.Name) //No localization!

                            }

                            globalScript += GetRemarketingScript("category", null, currentCategoryName, null);
                        }
                        else if (action.Equals("product", StringComparison.InvariantCultureIgnoreCase))
                        {
                            //current product ID
                            string currentProductIdStr = routeData.Values["productId"].ToString();

                            globalScript += GetRemarketingScript("product", currentProductIdStr, null, null);
                        }
                        else if (action.Equals("search", StringComparison.InvariantCultureIgnoreCase))
                        {
                            globalScript += GetRemarketingScript("search", null, null, null);
                        }
                        break;
                    case "shoppingcart":
                        var cart = _workContext.CurrentCustomer.ShoppingCartItems
                            .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                            .Where(sci => sci.StoreId == _storeContext.CurrentStore.Id).ToList();

                        globalScript += GetRemarketingScript("cart", null, null, cart);
                        break;
                    case "checkout":
                        if (action.Equals("completed", StringComparison.InvariantCultureIgnoreCase))
                        {
                            //We are in last step of checkout, we can use order total for conversion value
                            Order lastOrder = GetLastOrder();

                            globalScript += GetConversionScript(lastOrder);
                        }
                        else
                        {
                            globalScript += GetRemarketingScript("other", null, null, null);
                        }
                        break;
                }

            }
            catch (Exception ex)
            {
                _logger.InsertLog(Core.Domain.Logging.LogLevel.Error, "Error creating scripts for google adwords convertion tracking", ex.ToString());
            }
            return Content(globalScript);
        }

        private Order GetLastOrder()
        {
            var order = _orderService.SearchOrders(storeId: _storeContext.CurrentStore.Id,
                customerId: _workContext.CurrentCustomer.Id, pageSize: 1).FirstOrDefault();
            return order;
        }


        //<!-- Google Code for vente Conversion Page -->
        //<script type="text/javascript">
        //var google_tag_params = {
        //ecomm_prodid: 'REPLACE_WITH_VALUE',
        //ecomm_pagetype: 'REPLACE_WITH_VALUE',
        //ecomm_totalvalue: 'REPLACE_WITH_VALUE',
        //};
        //</script>
        //<script type="text/javascript">
        // /* <![CDATA[ */
        //var google_conversion_id = 234234234;
        //var google_conversion_language = "fr";
        //var google_conversion_format = "1";
        //var google_conversion_color = "ffffff";
        //var google_conversion_label = "34344FZDZEZ3R";
        //var google_conversion_value = 0;
        //var google_custom_params = window.google_tag_params;
        //var google_remarketing_only = true;
        // /* ]]> */
        //</script>
        //<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion.js">
        //</script>
        //<noscript>
        //<div style="display:inline;">
        //<img height="1" width="1" style="border-style:none;" alt="" src="http://www.googleadservices.com/pagead/conversion/1025115441/?label=zyqQEQsYro6AM&amp;guid=ON&amp;script=0"/>
        //</div>
        //</noscript>

        private string GetConversionScript(Order order)
        {
            GoogleAdwordsSettings googleAdwordsSettings = _settingService.LoadSetting<GoogleAdwordsSettings>(_storeContext.CurrentStore.Id);
            return InjectValuesInScript(googleAdwordsSettings.ConversionScript, googleAdwordsSettings.ConversionId, "purchase", googleAdwordsSettings.ConversionLabel, null, null, order, null);
        }

        private string GetRemarketingScript(string pageType, string productId, string categoryName, IList<ShoppingCartItem> cart)
        {
            GoogleAdwordsSettings googleAdwordsSettings = _settingService.LoadSetting<GoogleAdwordsSettings>(_storeContext.CurrentStore.Id);
            return InjectValuesInScript(googleAdwordsSettings.RemarketingScript, googleAdwordsSettings.ConversionId, pageType, null, productId, categoryName, null, cart);
        }

        private string InjectValuesInScript(string script, string conversionId, string pageType, string label, string productId, string categoryName, Order order, IList<ShoppingCartItem> cart)
        {
            //Set default or empty values
            String totalFormated = ToScriptFormat(0);
            String prodIdsFormated = "'" + productId + "'";
            //String valuesFormated = "'" + 0 + "'";

            //In case we have an order
            if (order != null)
            {
                totalFormated = ToScriptFormat( order.OrderTotal);
                prodIdsFormated = ToScriptFormat((from c in order.OrderItems select c.ProductId.ToString()).ToArray());
            }

            //In case we have a cart
            if (cart != null)
            {
                decimal subTotalWithoutDiscountBase = decimal.Zero;
                if (cart.Count > 0)
                {
                    decimal orderSubTotalDiscountAmountBase = decimal.Zero;
                    Discount orderSubTotalAppliedDiscount = null;
                    decimal subTotalWithDiscountBase = decimal.Zero;
                    var subTotalIncludingTax = _workContext.TaxDisplayType == TaxDisplayType.IncludingTax;
                    _orderTotalCalculationService.GetShoppingCartSubTotal(cart, subTotalIncludingTax, out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase);
                }

                totalFormated = ToScriptFormat( subTotalWithoutDiscountBase);
                prodIdsFormated = ToScriptFormat((from c in cart select c.ProductId.ToString()).ToArray());
            }


            script = script.Replace("{PAGETYPE}", "'" + pageType + "'");
            script = script.Replace("{PRODID}", prodIdsFormated);
            script = script.Replace("{CATEGORYNAME}", "'" + categoryName + "'");
            script = script.Replace("{VALUE}", totalFormated);
            script = script.Replace("{GOOGLECONVERSIONID}", conversionId);
            script = script.Replace("{GOOGLECONVERSIONLABEL}", label);

            //Remove optional and empty values
            script = script.Replace("ecomm_category: '',", "");
            script = script.Replace("ecomm_prodid: '',", "");
            script = script.Replace("ecomm_totalvalue: 0.00", "");


            if (this.HttpContext.Request.Url.Scheme == "https")
                script = script.Replace("http://", "https://");

            return script + "\n";
        }



        private string ToScriptFormat(decimal value)
        {
            return value.ToString("0.00", _usCulture);
        }
        private string ToScriptFormat(String[] strings)
        {
            if (strings == null || strings.Length == 0)
            {
                return "''";
            }
            else
            {
                StringBuilder strBuilder = new StringBuilder(strings.Length * 3 + 5);
                strBuilder.Append("'");
                strBuilder.Append(strings[0]);
                strBuilder.Append("'");
                if (strings.Length > 1)
                {
                    strBuilder.Insert(0, "[");
                    for (int i = 1; i < strings.Length; i++)
                    {
                        strBuilder.Append(",'");
                        strBuilder.Append(strings[i]);
                        strBuilder.Append("'");
                    }
                    strBuilder.Append("]");
                }
                return strBuilder.ToString();
            }
        }




    }
}